package com.yulinlin.jdbc.model.wrapper;

import com.yulinlin.jdbc.model.anno.*;
import com.yulinlin.lang.util.ReflectionUtil;
import com.yulinlin.lang.util.StringUtil;

import com.yulinlin.jdbc.session.SqlSession;
import com.yulinlin.core.wrapper.IColumnWrapper;
import com.yulinlin.core.wrapper.ISelectWrapper;
import com.yulinlin.core.wrapper.IStringConditionWrapper;
import com.yulinlin.core.wrapper.ITableWrapper;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

public class ModelSelectWrapper<E> {

    private ISelectWrapper<E,ModelSelectWrapper<E> > wrapper;

    private Class<E> clazz;

    public ModelSelectWrapper() {
        this.wrapper =  SqlSession.session().ofSelect(this);
    }

    public List<E> selectList(){

        SqlSession session =   SqlSession.session();

        return  session.selectList(this.wrapper,this.clazz);
    }

    public E selectOne(){

        SqlSession session =   SqlSession.session();

        return  session.selectOne(this.wrapper,this.clazz);

    }

    public Map<?,List<E>> selectByGroup(String key){
        SqlSession session =   SqlSession.session();
        return  session.selectByGroup(this.wrapper,this.clazz,key);
    }

    public Map<?,E> selectByMap(String key){
        SqlSession session =   SqlSession.session();
        return  session.selectByMap(this.wrapper,this.clazz,key);
    }


    public ISelectWrapper<E,ModelSelectWrapper<E>> wrapper(){
        return  this.wrapper;
    }

    public void parse(E obj){
        this.clazz = (Class<E>) obj.getClass();
        ITableWrapper fromWrapper =  wrapper.from();
        JoinTable table =  obj.getClass().getAnnotation(JoinTable.class);
        if(table != null){
            fromWrapper.table(table.value());
        }else{
            JoinTableList tableList =  this.getClass().getAnnotation(JoinTableList.class);
            for (JoinTable node: tableList.value()){
                if(node.value().length() > 0){
                    fromWrapper.table(table.value());
                }else{
                    String sql;
                    if(node.left().length() > 0){
                        sql = node.left();
                    }else{
                        sql = node.right();
                    }
                    String on = node.on();

                    if(node.join() == JoinEnum.left){
                        fromWrapper.left(sql).condition(on);
                    }else if(node.join() == JoinEnum.right){
                        fromWrapper.right(sql).condition(on);
                    }else if(node.join() == JoinEnum.inner){
                        fromWrapper.inner(sql).condition(on);
                    }
                }
            }
        }

        List<Field> fs =  ReflectionUtil.getAllDeclaredFields(obj.getClass());
        IColumnWrapper columnWrapper =  wrapper.data();

        for (Field f : fs){
            JoinField joinField =    f.getAnnotation(JoinField.class);
            if(joinField == null){
                continue;
            }
            String columnName =  joinField.columnName();
            if(columnName.length() == 0){
                columnName = StringUtil.javaToColumn(f.getName());
            }

            if(joinField.exist()){
                columnWrapper.columnAsName(columnName,f.getName());
            }

            JoinWhere joinWhere =    f.getAnnotation(JoinWhere.class);
            Object value =  ReflectionUtil.invokeGetter(obj,f.getName());
            if(ReflectionUtil.isNotEmpty(value)){
                IStringConditionWrapper whereWrapper ;
                if(joinWhere.where()){
                    whereWrapper = wrapper.where();
                }else{
                    whereWrapper = wrapper.having();
                }
                ConditionUtil.condition(whereWrapper,joinWhere.and(),columnName,joinWhere.condition(),value);
            }

            JoinGroup joinGroup =    f.getAnnotation(JoinGroup.class);
            if(joinGroup != null){
                wrapper.group(f.getName());
            }

            JoinOrder joinOrder =    f.getAnnotation(JoinOrder.class);
            if(joinOrder != null){
                if(joinOrder.asc()){
                    wrapper.orderByAsc(f.getName());
                }else{
                    wrapper.orderByDesc(f.getName());
                }

            }
        }

    }

    public static <E> ModelSelectWrapper newInstance(E obj){
        ModelSelectWrapper wrapper =   new ModelSelectWrapper();
        wrapper.parse(obj);
        return  wrapper;
    }


}
